/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package com.xy.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.xy.constants.CertificateTypeKey;
import com.xy.entity.CertificateApplyEntity;
import com.xy.entity.CertificateTempEntity;
import com.xy.entity.CertificateTypeEntity;
import com.xy.excel.*;
import com.xy.service.ICertificateApplyService;
import com.xy.service.ICertificateTempService;
import com.xy.service.ICertificateTypeService;
import com.xy.utils.IdCarUtils;
import com.xy.utils.IdCardCheckUtil;
import com.xy.vo.CertificateApplyVO;
import com.xy.vo.CertificateImpExcelVO;
import com.xy.vo.QueryCertificateVO;
import com.xy.vo.quer.AuditParam;
import com.xy.vo.result.MateVO;
import com.xy.wrapper.CertificateApplyWrapper;
import com.xy.wrapper.ExcelWapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import okhttp3.OkHttpClient;
import okhttp3.Request;

import org.apache.commons.io.IOUtils;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.excel.support.ExcelException;
import org.springblade.core.excel.util.ExcelUtil;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.api.IResultCode;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.BeanUtil;
import org.springblade.core.tool.utils.DateUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.system.cache.UserCache;
import org.springblade.system.entity.User;
import org.springblade.system.feign.IUserClient;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import static com.xy.constants.CertificateTypeKey.PER_CERTIFICATE_TYPE;
import static com.xy.constants.CertificateTypeKey.SER_CERTIFICATE_TYPE;
import static com.xy.utils.StrUtil.trim;
import static org.springblade.core.mp.support.Condition.getQueryWrapper;

/**
 * 证件申请表 控制器
 *
 * @author BladeX
 * @since 2023-07-21
 */
@RestController
@AllArgsConstructor
@Slf4j
@RequestMapping("blade-certificateApply/certificateApply")
@Api(value = "证件申请表", tags = "证件申请表接口")
public class CertificateApplyController extends BladeController {
	private final ICertificateApplyService certificateApplyService;
	private final ICertificateTypeService certificateTypeService;
	private final ICertificateTempService certificateTempService;
	private final IUserClient userClient;
	private final BladeRedis bladeRedis;


	/**
	 * 证件申请表 详情
	 */
	@GetMapping("/detail")
	@ApiOperationSupport(order = 1)
	@ApiOperation(value = "详情", notes = "传入certificateApply")
	public R<CertificateApplyVO> detail(CertificateApplyEntity certificateApply) {
		CertificateApplyEntity detail = certificateApplyService.getOne(Condition.getQueryWrapper(certificateApply));
		return R.data(CertificateApplyWrapper.build().entityVO(detail));
	}

	/**
	 * 证件申请表 分页
	 */
	@GetMapping("/list")
	@ApiOperationSupport(order = 2)
	@ApiOperation(value = "分页", notes = "传入certificateApply")
	public R<IPage<CertificateApplyVO>> list(@ApiIgnore @RequestParam Map<String, Object> certificateApply, Query query) {
		User userRleaName = null;
		if (certificateApply.containsKey("realName")) {
			Object realName = certificateApply.get("realName");
			if (Func.isNotEmpty(realName)) {
				certificateApply.remove("realName");
				userRleaName = UserCache.getUserRleaName(AuthUtil.getTenantId(), realName.toString());
			}
		}

		QueryWrapper<CertificateApplyEntity> queryWrapper = getQueryWrapper(certificateApply, CertificateApplyEntity.class);
		if (Func.isNotEmpty(userRleaName)) {
			queryWrapper.lambda().eq(CertificateApplyEntity::getCreateUser, userRleaName.getId());
		}
		queryWrapper.lambda().last("order by update_time DESC,id DESC");

		Condition.getQueryWrapper(certificateApply, CertificateApplyEntity.class);
		IPage<CertificateApplyEntity> pages = certificateApplyService.page(Condition.getPage(query), queryWrapper);
		return R.data(CertificateApplyWrapper.build().pageVO(pages));
	}

	@GetMapping("/all")
	@ApiOperationSupport(order = 2)
	@ApiOperation(value = "证件申请集合", notes = "传入certificateApply")
	public R<List<CertificateApplyVO>> all(@ApiIgnore @RequestParam Map<String, Object> certificateApply) {
		List<CertificateApplyEntity> pages = certificateApplyService.list(Condition.getQueryWrapper(certificateApply, CertificateApplyEntity.class));
		return R.data(CertificateApplyWrapper.build().listVO(pages));
	}

	/**
	 * 证件申请表 自定义分页
	 */
	@GetMapping("/page")
	@ApiOperationSupport(order = 3)
	@ApiOperation(value = "分页", notes = "传入certificateApply")
	public R<IPage<CertificateApplyVO>> page(CertificateApplyVO certificateApply, Query query) {
		IPage<CertificateApplyVO> pages = certificateApplyService.selectCertificateApplyPage(Condition.getPage(query), certificateApply);
		return R.data(pages);
	}


	/**
	 * 证件申请表 新增
	 */
	@PostMapping("/save")
	@ApiOperationSupport(order = 4)
	@ApiOperation(value = "新增", notes = "传入certificateApply")
	public R save(@Valid @RequestBody CertificateApplyEntity certificateApply) {
		certificateApply.setBizStatus(0);
		certificateApply.setAuditorCount(1);
		certificateApply.setAgentUserId(AuthUtil.getUserId());
		certificateApply.setAgentUser(AuthUtil.getUser().getUserName());
		if (IdCardCheckUtil.isPhone(certificateApply.getPhone()) && IdCardCheckUtil.isMobile(certificateApply.getPhone())) {
			return R.fail("联系电话不正确!");
		}
		if (Func.isEmpty(certificateApply.getCid())) {
			throw new ExcelException("请选择展商");
		}
		Long certificateTypeId = certificateApply.getCertificateTypeId();
		CertificateTypeEntity quer = new CertificateTypeEntity();
		quer.setTenantId(AuthUtil.getTenantId());
		quer.setId(certificateTypeId);
		CertificateTypeEntity one = certificateTypeService.getOne(getQueryWrapper(quer), false);
		if (Func.isEmpty(one)) {
			return R.fail("您没有权限申请该证件类型!");
		}
		setValue(certificateApply, one);
		CertificateTempEntity certificateTempEntities = certificateTempService.byUserId(AuthUtil.getUserId(), certificateApply.getCertificateTypeId());
		if (Func.isEmpty(certificateTempEntities)) {
			return R.fail("您没有权限申请该证件类型!");
		}
		Long aLong = certificateApplyService.countBy(certificateApply.getCertificateTypeId(), Func.toLong(certificateApply.getCid()));
		if (certificateTempEntities.getMaxValu().intValue() == aLong.intValue()) {
			return R.fail("您的证件可申请数量不足!");
		}
		certificateApply.setRealName(certificateTempEntities.getRealName());
		String forcing = certificateApply.getForcing();
		if (Func.isEmpty(forcing)) {
			LambdaQueryWrapper<CertificateApplyEntity> lambda = Wrappers.<CertificateApplyEntity>query().lambda();
			if (Func.isNotEmpty(certificateApply.getId())) {
				lambda.notIn(CertificateApplyEntity::getId, certificateApply.getId());
			}
			if (!Func.equals(certificateApply.getBizCode(), CertificateTypeKey.CAR_CERTIFICATE_TYPE)) {
				lambda.eq(CertificateApplyEntity::getIdCard, certificateApply.getIdCard());
				long one1 = certificateApplyService.count(lambda);
				if (one1 > 0) {
					return R.fail(certificateApply.getIdCard() + "该证件已经申请过了!");
				}
			} else {
				lambda.eq(CertificateApplyEntity::getLicensePlate, trim(certificateApply.getLicensePlate()));
				long one1 = certificateApplyService.count(lambda);
				if (one1 > 0) {
					return R.fail(certificateApply.getIdCard() + "该牌照已经申请过了!");
				}
			}
		}

		return R.status(certificateApplyService.save(certificateApply));
	}

	/**
	 * 证件申请表 修改
	 */
	@PostMapping("/update")
	@ApiOperationSupport(order = 5)
	@ApiOperation(value = "修改", notes = "传入certificateApply")
	public R update(@Valid @RequestBody CertificateApplyEntity certificateApply) {
		if (!Func.equals(certificateApply.getBizCode(), CertificateTypeKey.CAR_CERTIFICATE_TYPE)) {
			List<String> exclud = Arrays.asList("中国");
			if (exclud.contains(certificateApply.getNationality())) {
				IdCarUtils.Res res = IdCarUtils.idCarVerify(certificateApply.getName(), certificateApply.getIdCard());
				if (res.getCode() != 0) {
					throw new ExcelException(res.getMessage());
				}
				IdCarUtils.CarInfo result = res.getResult();
				if (!Func.equals(result.getRes(), "1")) {
					throw new ExcelException("身份证号与姓名不一致");
				}
			}
		}
		if (IdCardCheckUtil.isPhone(certificateApply.getPhone()) && IdCardCheckUtil.isMobile(certificateApply.getPhone())) {
			throw new ExcelException("联系电话不正确!");
		}
		if (Func.isNotEmpty(certificateApply.getId()) && Func.isNull(certificateApply.getBizStatus())) {
			throw new ExcelException("状态值传入错误!");
		}
		if (Func.isNotEmpty(certificateApply.getId()) && certificateApply.getBizStatus() == 1) {
			throw new ExcelException("证件已经审核通过，不能修改!");
		}
		return R.status(certificateApplyService.updateById(certificateApply));
	}

	@PostMapping("/sub/audit")
	@ApiOperationSupport(order = 7)
	@ApiOperation(value = "展商提交审核", notes = "传入ids")
	public R subAudit(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {

		if (Func.isEmpty(ids)) {
			throw new ExcelException("请选择要提交审核的数据");
		}
		LambdaQueryWrapper<CertificateApplyEntity> lambda = Wrappers.<CertificateApplyEntity>query().lambda();
		lambda.in(CertificateApplyEntity::getId, Func.toLongList(ids));
		List<CertificateApplyEntity> list = certificateApplyService.list(lambda);
		if (Func.isEmpty(list)) {
			throw new ExcelException("数据不存在");
		}
		list.stream().map(m -> {
			if (m.getBizStatus() == 1) {
				throw new ServiceException("该证件证件已审核通过了，不能在提交");
			}
			if (m.getBizStatus() == 3) {
				throw new ServiceException("该证件证件在审核中，请耐心等待审核结果");
			}
			m.setBizStatus(3);
			return m;
		}).collect(Collectors.toList());

		return R.status(certificateApplyService.updateBatchById(list));
	}

	@PostMapping("/audit")
	@ApiOperationSupport(order = 5)
	@ApiOperation(value = "审核", notes = "传入certificateApply")
	public R audit(@Valid @RequestBody AuditParam auditParam) {
		return R.status(certificateApplyService.audit(auditParam));
	}

	@PostMapping("/res/audit")
	@ApiOperationSupport(order = 5)
	@ApiOperation(value = "重新提交审核", notes = "传入ids")
	public R resAudit(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
		return R.status(certificateApplyService.resAudit(Func.toLongList(ids)));
	}

	@PostMapping("/submit/verify")
	@ApiOperationSupport(order = 6)
	@ApiOperation(value = "新增或修改数据检验-返回true校验通过，false,有提示有申请过了", notes = "传入certificateApply")
	public R<Boolean> submitVerify(@Valid @RequestBody CertificateApplyEntity certificateApply) {
		if (Func.isEmpty(certificateApply.getCid())) {
			throw new ExcelException("请选择展商");
		}
		if (!Func.equals(certificateApply.getBizCode(), CertificateTypeKey.CAR_CERTIFICATE_TYPE)) {
			List<String> exclud = Arrays.asList("中国");
			if (exclud.contains(certificateApply.getNationality())) {
				IdCarUtils.Res res = IdCarUtils.idCarVerify(certificateApply.getName(), certificateApply.getIdCard());
				if (res.getCode() != 0) {
					throw new ExcelException(res.getMessage());
				}
				IdCarUtils.CarInfo result = res.getResult();
				if (!Func.equals(result.getRes(), "1")) {
					throw new ExcelException("身份证号与姓名不一致");
				}
			}
		}
		if (IdCardCheckUtil.isPhone(certificateApply.getPhone()) && IdCardCheckUtil.isMobile(certificateApply.getPhone())) {
			return R.fail("联系电话不正确!");
		}
		Long certificateTypeId = certificateApply.getCertificateTypeId();
		CertificateTypeEntity quer = new CertificateTypeEntity();
		quer.setTenantId(AuthUtil.getTenantId());
		quer.setId(certificateTypeId);
		CertificateTypeEntity one = certificateTypeService.getOne(getQueryWrapper(quer), false);
		if (Func.isEmpty(one)) {
			return R.fail("您没有权限申请该证件类型!");
		}
		CertificateTempEntity certificateTempEntities = certificateTempService.byUserId(Func.toLong(certificateApply.getCid()), certificateApply.getCertificateTypeId());
		if (Func.isEmpty(certificateTempEntities)) {
			return R.fail("您没有权限申请该证件类型!");
		}
		Long aLong = certificateApplyService.countBy(certificateApply.getCertificateTypeId(), Func.toLong(certificateApply.getCid()));
		if (certificateTempEntities.getMaxValu().intValue() == aLong.intValue()) {
			return R.fail("您的证件可申请数量不足!");
		}
		String forcing = certificateApply.getForcing();
		if (Func.isEmpty(forcing)) {
			LambdaQueryWrapper<CertificateApplyEntity> lambda = Wrappers.<CertificateApplyEntity>query().lambda();
			if (Func.isNotEmpty(certificateApply.getId())) {
				lambda.notIn(CertificateApplyEntity::getId, certificateApply.getId());
			}
			if (!Func.equals(certificateApply.getBizCode(), CertificateTypeKey.CAR_CERTIFICATE_TYPE)) {
				lambda.eq(CertificateApplyEntity::getIdCard, certificateApply.getIdCard());
				long one1 = certificateApplyService.count(lambda);
				if (one1 > 0) {
					return R.data(false, certificateApply.getIdCard() + "该证件已经申请过了!");
				}
			} else {
				lambda.eq(CertificateApplyEntity::getLicensePlate, trim(certificateApply.getLicensePlate()));
				long one1 = certificateApplyService.count(lambda);
				if (one1 > 0) {
					return R.data(false, certificateApply.getIdCard() + "该牌照已经申请过了!");
				}
			}
		}

		return R.data(true);
	}

	/**
	 * 证件申请表 新增或修改
	 */
	@PostMapping("/submit")
	@ApiOperationSupport(order = 6)
	@ApiOperation(value = "新增或修改", notes = "传入certificateApply")
	public R submit(@Valid @RequestBody CertificateApplyEntity certificateApply) {
		if (Func.isEmpty(certificateApply.getId())) {
			certificateApply.setBizStatus(0);
			certificateApply.setAuditorCount(1);
			certificateApply.setAgentUserId(AuthUtil.getUserId());
			certificateApply.setAgentUser(AuthUtil.getUser().getUserName());
			certificateApply.setCreateUser(Func.toLong(certificateApply.getCid()));
		}
		if (Func.isEmpty(certificateApply.getCid())) {
			throw new ExcelException("请选择展商");
		}

		if (Func.equals(certificateApply.getBizCode(), CertificateTypeKey.CAR_CERTIFICATE_TYPE) && Func.notNull(certificateApply.getNumberOfSeats()) && certificateApply.getNumberOfSeats() < 0) {
			throw new ExcelException("人数不能为负数");
		}
		if (!Func.equals(certificateApply.getBizCode(), CertificateTypeKey.CAR_CERTIFICATE_TYPE)) {
			List<String> exclud = Arrays.asList("中国");
			if (exclud.contains(certificateApply.getNationality())) {
				IdCarUtils.Res res = IdCarUtils.idCarVerify(certificateApply.getName(), certificateApply.getIdCard());
				if (res.getCode() != 0) {
					throw new ExcelException(res.getMessage());
				}
				IdCarUtils.CarInfo result = res.getResult();
				if (!Func.equals(result.getRes(), "1")) {
					throw new ExcelException("身份证号与姓名不一致");

				}
			}
		}
		if (IdCardCheckUtil.isPhone(certificateApply.getPhone()) && IdCardCheckUtil.isMobile(certificateApply.getPhone())) {
			return R.fail("联系电话不正确!");
		}
		Long certificateTypeId = certificateApply.getCertificateTypeId();
		CertificateTypeEntity quer = new CertificateTypeEntity();
		quer.setTenantId(AuthUtil.getTenantId());
		quer.setId(certificateTypeId);
		CertificateTypeEntity one = certificateTypeService.getOne(getQueryWrapper(quer), false);
		if (Func.isEmpty(one)) {
			return R.fail("您没有权限申请该证件类型!");
		}
		CertificateTempEntity certificateTempEntities = certificateTempService.byUserId(Func.toLong(certificateApply.getCid()), certificateApply.getCertificateTypeId());
		if (Func.isEmpty(certificateTempEntities)) {
			return R.fail("您没有权限申请该证件类型!");
		}
		certificateApply.setRealName(certificateTempEntities.getRealName());
		Long aLong = certificateApplyService.countBy(certificateApply.getCertificateTypeId(), Func.toLong(certificateApply.getCid()));
		if (certificateTempEntities.getMaxValu().intValue() == aLong.intValue()) {
			return R.fail("您的证件可申请数量不足!");
		}
		String forcing = certificateApply.getForcing();
		if (Func.isEmpty(forcing)) {
			LambdaQueryWrapper<CertificateApplyEntity> lambda = Wrappers.<CertificateApplyEntity>query().lambda();
			if (Func.isNotEmpty(certificateApply.getId())) {
				lambda.notIn(CertificateApplyEntity::getId, certificateApply.getId());
			}
			if (!Func.equals(certificateApply.getBizCode(), CertificateTypeKey.CAR_CERTIFICATE_TYPE)) {
				lambda.eq(CertificateApplyEntity::getIdCard, certificateApply.getIdCard());
				long one1 = certificateApplyService.count(lambda);
				if (one1 > 0) {
					return R.fail(certificateApply.getIdCard() + "该证件已经申请过了!");
				}
			} else {
				lambda.eq(CertificateApplyEntity::getLicensePlate, trim(certificateApply.getLicensePlate()));
				long one1 = certificateApplyService.count(lambda);
				if (one1 > 0) {
					return R.fail(certificateApply.getIdCard() + "该牌照已经申请过了!");
				}
			}
		}
		boolean res = certificateApplyService.save(certificateApply);

		return R.status(res);
	}

	/**
	 * 证件申请表 删除
	 */
	@PostMapping("/remove")
	@ApiOperationSupport(order = 7)
	@ApiOperation(value = "逻辑删除", notes = "传入ids")
	public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
		return R.status(certificateApplyService.delete(Func.toLongList(ids)));
	}

	@GetMapping("/car/temp")
	@ApiOperationSupport(order = 18)
	@ApiOperation(value = "车辆证申请导入模板")
	public void carExporTemp(HttpServletResponse response) {
		List<VehicleExcelTemp> list = new ArrayList<>();
		ExcelUtil.export(response, "车辆证件申请数据" + DateUtil.time(), "车辆证件申请数据表", list, VehicleExcelTemp.class);
	}

	@ApiOperation(value = "导入车辆证申请", notes = "传入excel")
	@ApiOperationSupport(order = 19)
	@PostMapping("/car/import")
	public R<String> carImport(@RequestParam String cid, @RequestParam MultipartFile file) {
		VehicleImporter carImport = new VehicleImporter(certificateApplyService, false, cid);
		ExcelUtil.save(file, carImport, VehicleExcelTemp.class);
		return R.success("操作成功");
	}

	@GetMapping("/car/export")
	@ApiOperationSupport(order = 20)
	@ApiOperation(value = "导出车辆证件申请数据", notes = "传入 query")
	public void carExport(@ApiIgnore @RequestParam Map<String, Object> query, BladeUser bladeUser, HttpServletResponse response) {
		QueryWrapper<CertificateApplyEntity> queryWrapper = Condition.getQueryWrapper(query, CertificateApplyEntity.class);
		queryWrapper.lambda().eq(CertificateApplyEntity::getTenantId, bladeUser.getTenantId());
		queryWrapper.lambda().eq(CertificateApplyEntity::getBizCode, CertificateTypeKey.CAR_CERTIFICATE_TYPE);
		List<CertificateApplyEntity> list = certificateApplyService.list(queryWrapper);
		ExcelUtil.export(response, "车辆证件申请数据" + DateUtil.time(), "车辆证件申请数据表", ExcelWapper.build().listVe(list), VehicleExcel.class);
	}

	@GetMapping("/per/temp")
	@ApiOperationSupport(order = 21)
	@ApiOperation(value = "人员证件申请导入模板", notes = "传入 query")
	public void perExportTemp(HttpServletResponse response) {
		List<PersonnelExcelTemp> list = new ArrayList<>();
		ExcelUtil.export(response, "人员证件申请数据" + DateUtil.time(), "人员证件申请数据表", list, PersonnelExcelTemp.class);
	}

	@GetMapping("/ser/temp")
	@ApiOperationSupport(order = 21)
	@ApiOperation(value = "服务类型:人员证件申请导入模板", notes = "传入 query")
	public void serExportTemp(HttpServletResponse response) {
		List<PersonnelExcelTemp> list = new ArrayList<>();
		ExcelUtil.export(response, "服务证件申请数据" + DateUtil.time(), "服务证件申请数据表", list, PersonnelExcelTemp.class);
	}


	@ApiOperation(value = "导入服务类型:人员证件申请", notes = "传入excel")
	@ApiOperationSupport(order = 23)
	@PostMapping("/ser/import")
	public R<String> serImport(@RequestParam String cid, @RequestParam MultipartFile file) {
		PersonnelImporter perImport = new PersonnelImporter(certificateApplyService, false, SER_CERTIFICATE_TYPE, cid);
		ExcelUtil.save(file, perImport, PersonnelExcelTemp.class);
		return R.success("操作成功");
	}

	@ApiOperation(value = "导入人员证件申请", notes = "cid:展商userID,传入excel")
	@ApiOperationSupport(order = 24)
	@PostMapping("/per/import")

	public R<String> perImport(@RequestParam String cid, @RequestParam MultipartFile file) {
		PersonnelImporter perImport = new PersonnelImporter(certificateApplyService, false, PER_CERTIFICATE_TYPE, cid);
		ExcelUtil.save(file, perImport, PersonnelExcelTemp.class);
		return R.success("操作成功");
	}


	//@GetMapping("/per/export")
	//@ApiOperationSupport(order = 20)
	//@ApiOperation(value = "导出人员证件申请数据", notes = "传入 query")
	//public void perExport(@ApiIgnore @RequestParam Map<String, Object> query, BladeUser bladeUser, HttpServletResponse response) {
	//	QueryWrapper<CertificateApplyEntity> queryWrapper = Condition.getQueryWrapper(query, CertificateApplyEntity.class);
	//	queryWrapper.lambda().eq(CertificateApplyEntity::getTenantId, bladeUser.getTenantId());
	//	queryWrapper.lambda().eq(CertificateApplyEntity::getBizCode, CertificateTypeKey.PER_CERTIFICATE_TYPE);
	//	queryWrapper.lambda().eq(CertificateApplyEntity::getCreateUser, AuthUtil.getUserId());
	//	List<CertificateApplyEntity> list = certificateApplyService.list(queryWrapper);
	//	ExcelUtil.export(response, "人员证件申请数据" + DateUtil.time(), "人员证件申请数据", ExcelWapper.build().listPe(list), PersonnelExcel.class);
	//}
	//
	//@GetMapping("/ser/export")
	//@ApiOperationSupport(order = 20)
	//@ApiOperation(value = "导出服务证件申请数据", notes = "传入 query")
	//public void serExport(@ApiIgnore @RequestParam Map<String, Object> query, HttpServletResponse response) {
	//	QueryWrapper<CertificateApplyEntity> queryWrapper = Condition.getQueryWrapper(query, CertificateApplyEntity.class);
	//	queryWrapper.lambda().eq(CertificateApplyEntity::getTenantId, AuthUtil.getTenantId());
	//	queryWrapper.lambda().eq(CertificateApplyEntity::getCreateUser, AuthUtil.getUserId());
	//	queryWrapper.lambda().eq(CertificateApplyEntity::getBizCode, CertificateTypeKey.SER_CERTIFICATE_TYPE);
	//	List<CertificateApplyEntity> list = certificateApplyService.list(queryWrapper);
	//	ExcelUtil.export(response, "车辆证件申请数据" + DateUtil.time(), "车辆证件申请数据表", ExcelWapper.build().listPe(list), PersonnelExcel.class);
	//}


	@GetMapping("/export")
	@ApiOperationSupport(order = 21)
	@ApiOperation(value = "通用证件导出数据", notes = "传入  vo")
	public void auditExport(CertificateImpExcelVO vo, HttpServletResponse response) {
		if (Func.isEmpty(vo.getBizCode())) {
			throw new ExcelException("请选择要导出的审核证件类型");
		}
		List<String> bizCodes = Arrays.asList(Func.split(vo.getBizCode(), ",")).stream().distinct().collect(Collectors.toList());
		if (bizCodes.contains(CertificateTypeKey.CAR_CERTIFICATE_TYPE) && bizCodes.size() > 1) {
			throw new ExcelException("车辆证件类型不能组合导出");
		}
		LambdaQueryWrapper<CertificateApplyEntity> queryWrapper = Wrappers.lambdaQuery();
		if (Func.isNotEmpty(vo.getBizStatus())) {
			queryWrapper.eq(CertificateApplyEntity::getBizStatus, vo.getBizStatus());
		}
		if (Func.isNotEmpty(vo.getTypeKey())) {
			queryWrapper.eq(CertificateApplyEntity::getTypeKey, vo.getTypeKey());
		}
		if (Func.equals(vo.getFilt(), "1")) {
			queryWrapper.eq(CertificateApplyEntity::getCreateUser, AuthUtil.getUserId());
		}
		if (Func.equals(vo.getFilt(), "2")) {
			queryWrapper.eq(CertificateApplyEntity::getCreateDept, AuthUtil.getDeptId());
		}
		if (bizCodes.contains(CertificateTypeKey.CAR_CERTIFICATE_TYPE)) {
			queryWrapper.eq(CertificateApplyEntity::getBizCode, CertificateTypeKey.CAR_CERTIFICATE_TYPE);
			List<CertificateApplyEntity> list = certificateApplyService.list(queryWrapper);
			ExcelUtil.export(response, "车辆证件申请数据" + DateUtil.time(), "车辆证件申请数据表", ExcelWapper.build().listVe(list), VehicleExcel.class);
		} else if (bizCodes.contains(CertificateTypeKey.PER_CERTIFICATE_TYPE) || bizCodes.contains(CertificateTypeKey.SER_CERTIFICATE_TYPE)) {
			if (bizCodes.size() > 1) {
				queryWrapper.in(CertificateApplyEntity::getBizCode, bizCodes);
			} else {
				queryWrapper.eq(CertificateApplyEntity::getBizCode, bizCodes.get(0));
			}
			List<CertificateApplyEntity> list = certificateApplyService.list(queryWrapper);
			ExcelUtil.export(response, "证件申请数据" + DateUtil.time(), "证件申请数据", ExcelWapper.build().listPe(list), PersonnelExcel.class);
		} else {
			throw new ExcelException("未识别的证件类型，无法导出");
		}
	}

	@PostMapping("/mathc/file")
	@ApiOperationSupport(order = 7)
	@ApiOperation(value = "同步图片", notes = "传入 fileUrl  ")
	public R importImgUrl(@ApiParam(value = "文件目录", required = true) @RequestParam String fileUrl) {
		return R.status(certificateApplyService.matchingFileL(fileUrl));
	}


	private void setValue(CertificateApplyEntity applyEntity, CertificateTypeEntity type) {
		if (Func.isEmpty(applyEntity.getBizCode())) {
			applyEntity.setBizCode(type.getBizCode());
		}
		if (Func.isEmpty(applyEntity.getTypeKey())) {
			applyEntity.setTypeKey(type.getTypeKey());
		}
		if (Func.isEmpty(applyEntity.getTypeName())) {
			applyEntity.setTypeName(type.getTypeName());
		}
	}

	/**
	 * 头像匹配
	 *
	 * @param file 文件
	 * @return ObjectStat
	 */
	@SneakyThrows
	@PostMapping("/mate-file")
	@ApiOperation(value = "头像匹配", notes = "file 文件")
	public R<List<MateVO>> putFileAttach(@RequestParam MultipartFile file) {
		List<MateVO> mateVOList = certificateApplyService.putFileAttach(file);
		if (Func.isEmpty(mateVOList)) {
			return R.success(getResultCode());
		}
		return R.data(mateVOList);
	}

	/**
	 * 证件申请表 修改
	 */
	@PostMapping("/update-batch-id")
	@ApiOperationSupport(order = 5)
	@ApiOperation(value = "修改", notes = "传入certificateApply")
	public R update(@Valid @RequestBody List<CertificateApplyEntity> certificateApply) {

		return R.status(certificateApplyService.updateBatchById(certificateApply));
	}

	private IResultCode getResultCode() {
		IResultCode resultCode = new IResultCode() {
			@Override
			public String getMessage() {
				return "该照片未找到对应人员";
			}

			@Override
			public int getCode() {
				return 700;
			}
		};
		return resultCode;
	}

	/**
	 * 证件申请统计
	 */
	@GetMapping("/query-certificate")
	@ApiOperationSupport(order = 5)
	@ApiOperation(value = "证件申请统计", notes = "证件申请统计")
	public R<List<QueryCertificateVO>> queryCertificate(String deptId) {

		List<QueryCertificateVO> tempEntityList = certificateTempService.queryCertificate(deptId);

		Map<String, QueryCertificateVO> collect1 = tempEntityList.stream().collect(Collectors.toMap(QueryCertificateVO::getTypeName, t -> t));

		List<CertificateApplyEntity> certificateApplyEntityList = certificateApplyService.list(
			Wrappers.<CertificateApplyEntity>query().lambda().eq(CertificateApplyEntity::getCreateDept, deptId)
		);
		Map<String, List<CertificateApplyEntity>> longListMap = certificateApplyEntityList.stream().collect(Collectors.groupingBy(CertificateApplyEntity::getTypeName));

		List<QueryCertificateVO> certificateVOList = new ArrayList<>();

		collect1.entrySet().stream().forEach(o -> {
			QueryCertificateVO value = o.getValue();
			List<CertificateApplyEntity> certificateApplyEntityList1 = longListMap.get(o.getKey());
			if (Func.isEmpty(certificateApplyEntityList1)) {
				value.setTotalUsed(0);
			} else {
				value.setTotalUsed(certificateApplyEntityList1.size());
			}
			value.setTotalResidue(value.getTotalTypeNum() - value.getTotalUsed());
			value.setTypeName(collect1.get(o.getKey()).getTypeName());
			certificateVOList.add(value);
		});
		return R.data(certificateVOList);
	}

	/**
	 * 制证分页
	 */
	@GetMapping("/make-list")
	@ApiOperationSupport(order = 2)
	@ApiOperation(value = "制证分页", notes = "传入certificateApply")
	public R<IPage<CertificateApplyVO>> makeList(@ApiIgnore @RequestParam Map<String, Object> certificateApply, Query query) {
		User userRleaName = null;
		if (certificateApply.containsKey("realName")) {
			Object realName = certificateApply.get("realName");
			certificateApply.remove("realName");
			if (Func.isNotEmpty(realName)) {
				userRleaName = UserCache.getUserRleaName(AuthUtil.getTenantId(), realName.toString());
			}
		}

		QueryWrapper<CertificateApplyEntity> queryWrapper = getQueryWrapper(certificateApply, CertificateApplyEntity.class);
		if (Func.isNotEmpty(userRleaName)) {
			queryWrapper.lambda().eq(CertificateApplyEntity::getCreateUser, userRleaName.getId());
		}

		queryWrapper.lambda().notIn(CertificateApplyEntity::getBizCode, CertificateTypeKey.CAR_CERTIFICATE_TYPE);

		queryWrapper.lambda().eq(CertificateApplyEntity::getBizStatus, 1);
		queryWrapper.lambda().last("order by update_time DESC,id DESC");
		Condition.getQueryWrapper(certificateApply, CertificateApplyEntity.class);
		IPage<CertificateApplyEntity> pages = certificateApplyService.page(Condition.getPage(query), queryWrapper);
		return R.data(CertificateApplyWrapper.build().pageVO(pages));
	}

	/**
	 * 制证导出
	 */
	@GetMapping("/make-list-export")
	@ApiOperationSupport(order = 2)
	@ApiOperation(value = "制证导出", notes = "传入certificateApply")
	public void makeList(@RequestParam Map<String, Object> certificateApply, HttpServletResponse response) {
		String orderNo = "";
		if (certificateApply.containsKey("orderNo")) {
			orderNo = certificateApply.get("orderNo").toString();
			certificateApply.remove("orderNo");
		}
		User userRleaName = null;
		if (certificateApply.containsKey("realName")) {
			Object realName = certificateApply.get("realName");
			if (Func.isNotEmpty(realName)) {
				certificateApply.remove("realName");
				userRleaName = UserCache.getUserRleaName(AuthUtil.getTenantId(), realName.toString());
			}
		}

		QueryWrapper<CertificateApplyEntity> queryWrapper = getQueryWrapper(certificateApply, CertificateApplyEntity.class);
		queryWrapper.lambda().notIn(CertificateApplyEntity::getBizCode, CertificateTypeKey.CAR_CERTIFICATE_TYPE);
		queryWrapper.lambda().eq(CertificateApplyEntity::getBizStatus, 1);
		if (Func.isNotEmpty(userRleaName)) {
			queryWrapper.lambda().eq(CertificateApplyEntity::getCreateUser, userRleaName.getId());
		}
		queryWrapper.lambda().last("order by update_time DESC,id DESC");
		Condition.getQueryWrapper(certificateApply, CertificateApplyEntity.class);

		List<CertificateApplyEntity> applyEntities = certificateApplyService.list(queryWrapper);
		List<PersonnelExcel> excelList = new ArrayList<>();
		String finalOrderNo = orderNo;
		applyEntities.forEach(o -> {
			o.setOrderNo(finalOrderNo);
			o.setMakeState("1");
			excelList.add(ExcelWapper.build().toPe(o));
		});
		certificateApplyService.updateBatchById(applyEntities);
		ExcelUtil.export(response, "制证数据" + orderNo, "制证数据" + orderNo, excelList, PersonnelExcel.class);
	}

	@GetMapping("/user/photo")
	@ApiOperationSupport(order = 20)
	@ApiOperation(value = "制证导出图片", notes = "传入 query")
	@SneakyThrows
	public void userPhoto(String orderNo, HttpServletResponse response) {
		QueryWrapper<CertificateApplyEntity> queryWrapper = new QueryWrapper<>();
		queryWrapper.lambda().eq(CertificateApplyEntity::getOrderNo, orderNo);
		List<CertificateApplyEntity> list = certificateApplyService.list(queryWrapper);
		ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
		ZipOutputStream zip = new ZipOutputStream(outputStream);
		list.forEach(o -> {
			String url = o.getUrl();
			if (Func.isNotEmpty(url)) {
				byte[] byteArray = statFileStream(url);
				zipPhoto(o.getIdCard() + ".jpg", zip, byteArray);
			}
		});

		IOUtils.closeQuietly(zip);
		byte[] byteArray = outputStream.toByteArray();
		genCode(response, byteArray, orderNo);

	}

	@GetMapping("/getNumber")
	public void userPhoto() {
		QueryWrapper<CertificateApplyEntity> queryWrapper = new QueryWrapper<>();
		queryWrapper.lambda().eq(CertificateApplyEntity::getBizStatus, 1);
		queryWrapper.lambda().last("and card_number is null");

		List<CertificateApplyEntity> list = certificateApplyService.list(queryWrapper);
		List<CertificateApplyEntity> list1 = new ArrayList<>();
		list.forEach(o->{
			CertificateTypeEntity entity1 = certificateTypeService.getById(o.getCertificateTypeId());
//			String serialStr = getSerialStr(entity1);
//			if(Func.isNotEmpty(serialStr)){
//				o.setSerialNumber(serialStr);
//			}
			String cardNumberStr = getCardNumberStr(entity1);
			if(Func.isNotEmpty(cardNumberStr)){
				o.setCardNumber(cardNumberStr);
				list1.add(o);
			}
		});
		certificateApplyService.updateBatchById(list1);
	}
	public String getSerialStr(CertificateTypeEntity entity){
		String key ="crm:type:serial".concat(Func.toStr(entity.getId()));
		Object o = bladeRedis.get(key);

		if(Func.isEmpty(o)){
			if(Func.isEmpty(entity.getSerialNumber())){
				return  "";
			}
			bladeRedis.set(key,entity.getSerialNumber());
			String newStrNum = String.format("%0"+entity.getSerialNumber().length()+"d", Func.toInt(entity.getSerialNumber()));
			String concat = entity.getSerialPrefix().concat(newStrNum);
			return concat;
		}
		int i = Func.toInt(o) + 1;
		bladeRedis.set(key,i);
		String newStrNum = String.format("%05d",i);
		return  entity.getSerialPrefix().concat(newStrNum);
	}
	public String getCardNumberStr(CertificateTypeEntity entity){
		String key ="crm:type:card:number".concat(Func.toStr(entity.getId()));
		Object o = bladeRedis.get(key);
		if(Func.isEmpty(o)){
			if(Func.isEmpty(entity.getCardNumber())){
				return  "";
			}
			int i = Func.toInt(entity.getCardNumber()) + 1;
			bladeRedis.set(key,i);
			return Func.toStr(i);
		}
		int i = Func.toInt(o) + 1;
		bladeRedis.set(key,i);
		return Func.toStr(i);
	}

	/**
	 * 生成zip文件
	 */
	private void genCode(HttpServletResponse response, byte[] data, String fileName) throws IOException {
		response.reset();
		response.addHeader("Access-Control-Allow-Origin", "*");
		response.addHeader("Access-Control-Expose-Headers", "Content-Disposition");
		response.setHeader("Content-Disposition", "attachment; filename=" + fileName + ".zip" + "");
		response.addHeader("Content-Length", "" + data.length);
		response.setContentType("application/octet-stream; charset=UTF-8");

		IOUtils.write(data, response.getOutputStream());
	}

	public void zipPhoto(String fileName, ZipOutputStream zip, byte[] byteArray) {
		try {
			StringWriter sw = new StringWriter();
			// 添加到zip
			zip.putNextEntry(new ZipEntry(fileName));
			zip.write(byteArray);
			zip.flush();
			zip.closeEntry();
		} catch (IOException e) {
			log.error("渲染模板失败，表名：" + fileName, e);
		}
	}

	/**
	 * 获取文件信息
	 *
	 * @return InputStream
	 */

	@SneakyThrows
	public byte[] statFileStream(String url) {

		OkHttpClient client = new OkHttpClient();
		Request req = new Request.Builder().url(url).build();
		okhttp3.Response resp = null;
		resp = client.newCall(req).execute();
		if (resp.isSuccessful()) {
			okhttp3.ResponseBody body = resp.body();
			return body.bytes();
		}
		log.info("当前文件下载失败{}请检查文件是否存在或者文件是否为私有文件", url);
		return null;
	}
}
